package main

import (
	"fmt"
	"io/fs"
	"os"
	"path"
	"path/filepath"
)

type Node struct {
	//The type of the Node(File or Dir).
	Type FileType
	//The name of the Node.
	Name string
	//The son nodes of the Node.
	SonNodes []Node
	//The number of the son nodes.
	Length int
	//The layer of the Node in main dir.
	//
	//The Layer of main dir is 0.
	Layer int
	//The absolute path of the Node.
	Path string
	//Whether you have permission to open files.
	HasPermission bool
	//The target of the Symlink.
	SymLinkTarget string
}

func (n *Node) Build(all bool) {
	sd, err := os.ReadDir(n.Path)
	if err != nil {
		n.HasPermission = false
	} else {
		n.HasPermission = true
	}
	n.Length = len(sd)
	for _, entry := range sd {
		if !all && entry.Name()[0] == '.' {
			continue
		}
		node := Node{
			Name:  entry.Name(),
			Path:  path.Join(n.Path, entry.Name()),
			Layer: n.Layer + 1,
		}
		i, err := entry.Info()
		if err != nil {
			continue
		}
		m := i.Mode()
		if m&fs.ModeDir == fs.ModeDir {
			FileQuantityStatistics.NumberOfDirectory += 1
		} else {
			FileQuantityStatistics.NumberOfFile += 1
		}
		if m&fs.ModeDir == fs.ModeDir {
			node.Type = Dir
			node.Build(all)
		} else if m&fs.ModeSymlink == fs.ModeSymlink {
			node.Type = Symlink
			node.SymLinkTarget, _ = filepath.EvalSymlinks(node.Path)
		} else if m&fs.ModeDevice == fs.ModeDevice || m&fs.ModeCharDevice == fs.ModeCharDevice {
			node.Type = Device
		} else {
			node.Type = File
		}
		n.SonNodes = append(n.SonNodes, node)
	}
}

func (n *Node) Print(r string, s string, c string, d string) {
	var cname = ColorFileName(n.Name, n.Type)
	j := fmt.Sprintf("%s %s", s, c)
	fmt.Printf("%s %s─ %s", j, r, cname)
	if n.Type == Symlink {
		fmt.Print(" -> ", n.SymLinkTarget)
	}
	fmt.Print("\n")
	if n.Type == Dir {
		if n.HasPermission {
			for i, node := range n.SonNodes {
				if i == len(n.SonNodes)-1 {
					node.Print("└", j, d, " ")
				} else {
					node.Print("├", j, d, "│")
				}
			}
		} else {
			fmt.Printf("%s %s %s─ %s\n", j, d, "└", "/?......")
		}
	}
}
